﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Joy.Erp.BasicArchives.Core;
using Joy.Erp.BasicArchives.ItemMasters;
using Joy.Erp.BasicArchives.Production;
using Joy.Erp.Ufida.Core;
using Microsoft.Extensions.Logging;

namespace Joy.Erp.Ufida.Production
{
    public class PlanOrderSyncAppService : UfidaAppService, IPlanOrderSyncAppService
    {
        protected IPlanOrderRepository PlanOrderRepository => LazyServiceProvider.LazyGetRequiredService<IPlanOrderRepository>();
        protected IPlanOrderTypeRepository PlanOrderTypeRepository => LazyServiceProvider.LazyGetRequiredService<IPlanOrderTypeRepository>();
        protected IItemMasterRepository ItemMasterRepository => LazyServiceProvider.LazyGetRequiredService<IItemMasterRepository>();
        protected IPlanOrderUfidaAppService PlanOrderUfidaAppService => LazyServiceProvider.LazyGetRequiredService<IPlanOrderUfidaAppService>();

        public async Task<AnalysisDto> AnalyzeAsync(DateTime start, DateTime end)
        {
            var analysisDto = new AnalysisDto();
            analysisDto.Id = typeof(PlanOrder).FullName;

            // 获取U9数据的ID列表（去重）
            var u9list = await PlanOrderUfidaAppService.GetAllAsync(start, end);
            var u9Ids = u9list.Select(x => x.ID.ToString()).Distinct().ToHashSet();
            analysisDto.U9Count = u9Ids.Count;

            // 使用数据库查询优化，只查询需要的字段
            var pmcQuery = await PlanOrderRepository.GetQueryableAsync();

            // 获取PMC总数
            analysisDto.Count = await AsyncExecuter.CountAsync(
                pmcQuery.Where(x =>
                    !x.IsDeleted
                    && x.SourceCreatedOn >= start
                    && x.SourceCreatedOn <= end
                    && x.SourceType == SourceConfig.SourceType
                )
            );

            // 获取已同步的SourceKey列表
            var syncedSourceKeys = await AsyncExecuter.ToListAsync(
                pmcQuery
                    .Where(x =>
                        !x.IsDeleted
                        && x.SourceCreatedOn >= start
                        && x.SourceCreatedOn <= end
                        && x.SourceType == SourceConfig.SourceType
                    )
                    .Select(x => x.SourceKey)
            );

            // 使用 HashSet 快速计算已同步数量
            analysisDto.AsyncCount = syncedSourceKeys.Count(key => u9Ids.Contains(key));
            analysisDto.UnasyncCount = analysisDto.U9Count - analysisDto.AsyncCount;
            analysisDto.SelfCount = analysisDto.Count - analysisDto.AsyncCount;

            return analysisDto;
        }

        public async Task<List<long>> GetUnasyncIds(DateTime start, DateTime end)
        {
            // 获取U9的所有ID（去重）
            var u9list = await PlanOrderUfidaAppService.GetAllAsync(start, end);
            var u9Ids = u9list.Select(x => x.ID).Distinct().ToList();

            // 使用数据库查询，只查询已同步的SourceKey
            var pmcQuery = await PlanOrderRepository.GetQueryableAsync();
            var syncedSourceKeys = await AsyncExecuter.ToListAsync(
                pmcQuery
                    .Where(x =>
                        !x.IsDeleted
                        && x.SourceCreatedOn >= start
                        && x.SourceCreatedOn <= end
                        && x.SourceType == SourceConfig.SourceType
                    )
                    .Select(x => x.SourceKey)
            );

            // 使用 HashSet 优化查找性能，时间复杂度从 O(n²) 降到 O(n)
            var syncedSourceKeySet = new HashSet<string>(syncedSourceKeys);

            // 找出未同步的ID
            var unasyncIds = u9Ids
                .Where(id => !syncedSourceKeySet.Contains(id.ToString()))
                .ToList();

            return unasyncIds;
        }

        public async Task<int> CreateByIds‌Async(long[] ids, DateTime start, DateTime end)
        {
            if (ids == null || ids.Length == 0)
                return 0;
            var successCount = 0;
            var pmcQuery = await PlanOrderRepository.GetQueryableAsync();
            var idStrings = ids.Select(id => id.ToString()).ToList();
            var existingSourceKeys = await AsyncExecuter.ToListAsync(
                pmcQuery
                    .Where(x =>
                        idStrings.Contains(x.SourceKey) && x.SourceType == SourceConfig.SourceType
                    )
                    .Select(x => x.SourceKey)
            );
            var existingSet = new HashSet<string>(existingSourceKeys);
            var needCreateIds = ids.Where(id => !existingSet.Contains(id.ToString())).ToList();
            if (needCreateIds.Count == 0)
                return ids.Length;
            Logger.LogInformation($"[批量同步-计划订单] 开始处理 {needCreateIds.Count} 条");

            var allU9DataDict = new Dictionary<long, List<PlanOrderUfidaDto>>();
            foreach (var id in needCreateIds)
            {
                try
                {
                    var items = await PlanOrderUfidaAppService.GetLinesAsync(id, start, end);
                    if (items != null && items.Count > 0)
                        allU9DataDict[id] = items;
                }
                catch (Exception ex)
                {
                    Logger.LogWarning(ex, $"[批量同步-计划订单] 获取U9数据失败，Id: {id}");
                }
            }
            if (allU9DataDict.Count == 0)
                return existingSet.Count;

            var allTypeIds = allU9DataDict.Values.SelectMany(x => x).Select(x => x.SuggestSupplyTypeId.ToString()).Distinct().ToList();
            var allItemMasterIds = allU9DataDict.Values.SelectMany(x => x).Select(x => x.ItemMaster.ToString()).Distinct().ToList();
            var typeCacheDict = await BatchLoadPlanOrderTypes(allTypeIds);
            var itemMasterCacheDict = await BatchLoadItemMasters(allItemMasterIds);

            var entities = new List<PlanOrder>();
            foreach (var kvp in allU9DataDict)
            {
                try
                {
                    var entity = GetEntity(kvp.Value, typeCacheDict, itemMasterCacheDict);
                    if (entity != null)
                        entities.Add(entity);
                }
                catch (Exception ex)
                {
                    Logger.LogWarning(ex, $"[批量同步-计划订单] 创建实体失败，Id: {kvp.Key}");
                }
            }

            if (entities.Count > 0)
            {
                using (
                    var uow = UnitOfWorkManager.Begin(
                        new Volo.Abp.Uow.AbpUnitOfWorkOptions(),
                        requiresNew: true
                    )
                )
                {
                    try
                    {
                        await PlanOrderRepository.BulkInsertAsync(entities, autoSave: false);
                        await uow.CompleteAsync();
                        successCount = entities.Count;
                    }
                    catch (Exception ex)
                    {
                        Logger.LogWarning(ex, $"[批量同步-计划订单] 批量插入失败，{ex.Message}");
                    }
                }
            }

            Logger.LogInformation($"[批量同步-计划订单] 完成！");
            return successCount + existingSet.Count;
        }

        public async Task<List<long>> GetSyncedIds(DateTime start, DateTime end)
        {
            var pmcQuery = await PlanOrderRepository.GetQueryableAsync();
            var syncedSourceKeys = await AsyncExecuter.ToListAsync(
                pmcQuery
                    .Where(x =>
                        !x.IsDeleted
                        && x.SourceCreatedOn >= start
                        && x.SourceCreatedOn <= end
                        && x.SourceType == SourceConfig.SourceType
                    )
                    .Select(x => x.SourceKey)
            );

            var result = new List<long>();
            foreach (var key in syncedSourceKeys)
            {
                if (long.TryParse(key, out var id))
                {
                    result.Add(id);
                }
            }

            return result;
        }

        public async Task<int> UpdateByIdsAsync(long[] ids, DateTime start, DateTime end)
        {
            if (ids == null || ids.Length == 0)
                return 0;
            Logger.LogInformation($"[批量同步-计划订单] 开始处理 {ids.Length} 条更新");

            var pmcQuery = await PlanOrderRepository.WithDetailsAsync(x => x.Children);
            var idStrings = ids.Select(x => x.ToString()).ToList();
            var existingEntities = await AsyncExecuter.ToListAsync(
                pmcQuery.Where(x =>
                    idStrings.Contains(x.SourceKey) && x.SourceType == SourceConfig.SourceType
                )
            );
            if (existingEntities.Count == 0)
            {
                Logger.LogWarning($"[批量同步-计划订单] 没有找到需要更新的记录");
                return 0;
            }

            var entityDict = existingEntities.ToDictionary(x => x.SourceKey, x => x);
            var needHandleIds = ids.Where(id => entityDict.ContainsKey(id.ToString())).ToList();
            if (needHandleIds.Count == 0)
                return 0;

            var allU9DataDict = new Dictionary<long, List<PlanOrderUfidaDto>>();
            var entitiesToDelete = new List<PlanOrder>();
            foreach (var id in needHandleIds)
            {
                if (!entityDict.TryGetValue(id.ToString(), out var entity))
                    continue;

                try
                {
                    var items = await PlanOrderUfidaAppService.GetLinesAsync(id, start, end);
                    if (items != null && items.Count > 0)
                    {
                        allU9DataDict[id] = items;
                    }
                    else
                    {
                        entitiesToDelete.Add(entity);
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogWarning(ex, $"[批量同步-计划订单] 获取U9数据失败，Id: {id}");
                }
            }

            var entitiesToUpdate = new List<PlanOrder>();
            if (allU9DataDict.Count > 0)
            {
                var allTypeIds = allU9DataDict.Values.SelectMany(x => x).Select(x => x.SuggestSupplyTypeId.ToString()).Distinct().ToList();
                var typeCacheDict = await BatchLoadPlanOrderTypes(allTypeIds);

                var allItemMasterIds = allU9DataDict.Values.SelectMany(x => x).Select(x => x.ItemMaster.ToString()).Distinct().ToList();
                var itemMasterCacheDict = await BatchLoadItemMasters(allItemMasterIds);

                foreach (var kvp in allU9DataDict)
                {
                    var id = kvp.Key;
                    var u9Items = kvp.Value;
                    if (!entityDict.TryGetValue(id.ToString(), out var entity))
                        continue;
                    if (u9Items.Count == 0)
                        continue;

                    try
                    {
                        entity.Code = u9Items[0].DocNo;
                        entity.BusinessDate = u9Items[0].DemandDate ?? DateTime.Now.Date;
                        entity.DocumentStatus = ToDocumentStatus();
                        entity.SourceCreatedOn = u9Items[0].CreatedOn;
                        entity.SupplyType = (SupplyType)u9Items[0].SuggestSupplyType;

                        if (typeCacheDict.TryGetValue(u9Items[0].SuggestSupplyTypeId.ToString(), out var orderTypeDto))
                        {
                            entity.OrderTypeId = orderTypeDto.Id;
                        }

                        if (itemMasterCacheDict.TryGetValue(u9Items[0].ItemMaster.ToString(), out var itemMasterDto))
                        {
                            entity.ItemMasterId = itemMasterDto.Id;
                            entity.ItemCode = itemMasterDto.Code;
                            entity.ItemName = itemMasterDto.Name;
                            entity.ItemSpec = itemMasterDto.Spec;
                        }

                        entity.Quantity = u9Items[0].Qty;
                        entity.ReleaseQuantity = u9Items[0].ReleasedQty;

                        var existingLinesDict = entity.Children.ToDictionary(x => x.SourceKey);
                        var processedKeys = new HashSet<string>();
                        var lineNo = 1;

                        foreach (var item in u9Items)
                        {
                            //if (!line.TryGetValue(item.ItemMaster.ToString(), out var itemMasterDto)) continue;

                            //var sourceKey = item.ID.ToString();
                            //processedKeys.Add(sourceKey);

                            //if (existingLinesDict.TryGetValue(sourceKey, out var line))
                            //{
                            //    line.LineNo = lineNo;
                            //    line.ItemMasterId = itemMasterDto.Id;
                            //    line.ItemCode = itemMasterDto.Code;
                            //    line.ItemName = itemMasterDto.Name;
                            //    line.ItemSpec = itemMasterDto.Spec;
                            //    line.Quantity = item.Qty;
                            //    line.IssuedQuantity = item.ReleasedQty;
                            //    line.SourceCreatedOn = item.CreatedOn;
                            //}
                            //else
                            //{
                            //    var newLine = new PlanOrderPreparation
                            //    {
                            //        SourceType = SourceConfig.SourceType,
                            //        SourceKey = sourceKey,
                            //        SourceCreatedOn = item.CreatedOn,
                            //        LineNo = lineNo,
                            //        ItemMasterId = itemMasterDto.Id,
                            //        ItemCode = itemMasterDto.Code,
                            //        ItemName = itemMasterDto.Name,
                            //        ItemSpec = itemMasterDto.Spec,
                            //        Quantity = item.Qty,
                            //        IssuedQuantity = item.ReleasedQty,
                            //        DocumentId = entity.Id,
                            //        CreationTime = Clock.Now,
                            //        CreatorId = CurrentUser.Id,
                            //    };
                            //    newLine.SetId(GuidGenerator.Create());
                            //    entity.Children.Add(newLine);
                            //}

                            lineNo++;
                        }

                        var linesToRemove = entity.Children.Where(line => !processedKeys.Contains(line.SourceKey)).ToList();
                        foreach (var line in linesToRemove)
                        {
                            entity.Children.Remove(line);
                        }

                        entitiesToUpdate.Add(entity);
                    }
                    catch (Exception ex)
                    {
                        Logger.LogWarning(ex, $"[批量同步-计划订单] 修改实体失败，Id: {id}");
                    }
                }
            }

            if (entitiesToUpdate.Count == 0 && entitiesToDelete.Count == 0)
            {
                Logger.LogInformation($"[批量同步-计划订单] 无需更新或删除记录");
                return 0;
            }

            var updateCount = 0;
            var deleteCount = 0;
            using (
                var uow = UnitOfWorkManager.Begin(
                    new Volo.Abp.Uow.AbpUnitOfWorkOptions(),
                    requiresNew: true
                )
            )
            {
                try
                {
                    if (entitiesToUpdate.Count > 0)
                    {
                        await PlanOrderRepository.BulkUpdateAsync(
                            entitiesToUpdate,
                            autoSave: false
                        );
                        updateCount = entitiesToUpdate.Count;
                    }

                    if (entitiesToDelete.Count > 0)
                    {
                        await PlanOrderRepository.BulkDeleteAsync(
                            entitiesToDelete,
                            autoSave: false
                        );
                        deleteCount = entitiesToDelete.Count;
                    }

                    await uow.CompleteAsync();
                }
                catch (Exception ex)
                {
                    Logger.LogWarning(ex, $"[批量同步-计划订单] 批量更新/删除失败，{ex.Message}");
                }
            }

            Logger.LogInformation($"[批量同步-计划订单] 完成！成功更新 {updateCount} 条，删除 {deleteCount} 条");
            return updateCount + deleteCount;
        }

        private DocumentStatus ToDocumentStatus()
        {
            return DocumentStatus.Open;
        }

        private async Task<Dictionary<string, PlanOrderTypeDto>> BatchLoadPlanOrderTypes(List<string> sourceKeys)
        {
            if (sourceKeys == null || sourceKeys.Count == 0)
                return new Dictionary<string, PlanOrderTypeDto>();

            var query = await PlanOrderTypeRepository.GetQueryableAsync();
            var items = await AsyncExecuter.ToListAsync(
                query.Where(x =>
                    sourceKeys.Contains(x.SourceKey) && x.SourceType == SourceConfig.SourceType
                )
            );

            return items.ToDictionary(
                x => x.SourceKey,
                x => ObjectMapper.Map<PlanOrderType, PlanOrderTypeDto>(x)
            );
        }

        private async Task<Dictionary<string, ItemMasterDto>> BatchLoadItemMasters(List<string> sourceKeys)
        {
            if (sourceKeys == null || sourceKeys.Count == 0)
                return new Dictionary<string, ItemMasterDto>();

            var query = await ItemMasterRepository.GetQueryableAsync();
            var items = await AsyncExecuter.ToListAsync(
                query.Where(x =>
                    sourceKeys.Contains(x.SourceKey) && x.SourceType == SourceConfig.SourceType
                )
            );

            return items.ToDictionary(
                x => x.SourceKey,
                x => ObjectMapper.Map<ItemMaster, ItemMasterDto>(x)
            );
        }

        private PlanOrder GetEntity(
            List<PlanOrderUfidaDto> items,
            Dictionary<string, PlanOrderTypeDto> typeCacheDict,
            Dictionary<string, ItemMasterDto> itemMasterCacheDict
        )
        {
            if (items == null || items.Count == 0)
                return null;
            if (!typeCacheDict.TryGetValue(items[0].SuggestSupplyTypeId.ToString(), out var typeDto))
                return null;
            if (!itemMasterCacheDict.TryGetValue(items[0].ItemMaster.ToString(), out var itemMasterDto))
                return null;

            var entityId = GuidGenerator.Create();
            var entity = new PlanOrder
            {
                SourceType = SourceConfig.SourceType,
                SourceKey = items[0].ID.ToString(),
                SourceCreatedOn = items[0].CreatedOn,
                Code = items[0].DocNo,
                BusinessDate = items[0].DemandDate ?? DateTime.Now.Date,
                DocumentStatus = ToDocumentStatus(),
                OrderTypeId = typeDto.Id,
                SupplyType = (SupplyType)items[0].SuggestSupplyType,
                ItemMasterId = itemMasterDto.Id,
                ItemCode = itemMasterDto.Code,
                ItemName = itemMasterDto.Name,
                ItemSpec = itemMasterDto.Spec,
                Quantity = items[0].Qty,
                ReleaseQuantity = items[0].ReleasedQty,
                Mark = "",
                CreationTime = Clock.Now,
                CreatorId = CurrentUser.Id,
                TenantId = CurrentTenant.Id,
            };
            entity.SetId(entityId);

            var lineNo = 1;
            foreach (var item in items)
            {
                if (!itemMasterCacheDict.TryGetValue(item.ItemMaster.ToString(), out var lineItemMasterDto))
                    continue;

                var line = new PlanOrderPreparation
                {
                    SourceType = SourceConfig.SourceType,
                    SourceKey = item.ID.ToString(),
                    SourceCreatedOn = item.CreatedOn,
                    LineNo = lineNo,
                    ItemMasterId = lineItemMasterDto.Id,
                    ItemCode = lineItemMasterDto.Code,
                    ItemName = lineItemMasterDto.Name,
                    ItemSpec = lineItemMasterDto.Spec,
                    Quantity = item.Qty,
                    IssuedQuantity = item.ReleasedQty,
                    DocumentId = entityId,
                    CreationTime = Clock.Now,
                    CreatorId = CurrentUser.Id,
                };
                line.SetId(GuidGenerator.Create());
                entity.Children.Add(line);

                lineNo++;
            }

            return entity;
        }

    }
}
